import {Injectable} from '@angular/core';
import {interval, Subject,Observable} from 'rxjs';
import { NzNotificationService } from 'ng-zorro-antd';
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
import {  NzMessageService } from 'ng-zorro-antd';
import { filter, map } from 'rxjs/operators';
import { UtilService } from 'shared/services/util.service';
import { PagesService } from 'services/pages.service';
import { RequestService } from 'services/request.service';
declare var layui: any;
declare var layer: any;
declare var $: any;


/**
 * websocket服务
 */
@Injectable({
  providedIn: 'root'
})
export class SocketService {

  private subject = new Subject<any>();
   /**
   * content模块里面进行信息传输，类似广播
   * @param type 发送的信息类型
   */
   sendMessages(num) {
    this.subject.next(num);
   }
   /**
   * 清理消息
   */
   clearMessage() {
    this.subject.next();
   }
   /**
   * 获得消息
   * @returns {Observable<any>} 返回消息监听
   */
   getMessage(): Observable<any> {
    return this.subject.asObservable();
   }
  
  messageSubject;                                 // subject对象,用于发送事件
  private url;                                    // 默认请求的url
  private webSocket: WebSocket;                   // websocket对象
  connectSuccess = false;                         // websocket 连接成功
  period = 6 * 1000 * 1;                        // 1分钟检查一次
  serverTimeoutSubscription = null;               // 定时检测连接对象
  reconnectFlag = false;                          // 重连
  reconnectPeriod = 5 * 1000;                     // 重连失败,则5秒钟重连一次
  reconnectSubscription = null;                   // 重连订阅对象
  runTimeSubscription;                            // 记录运行连接subscription
  runTimePeriod = 60 * 10000;                     // 记录运行连接时间

  constructor(
    private route: ActivatedRoute,
    private router: Router,
    private activatedRoute: ActivatedRoute,
    private notification: NzNotificationService,
    public utilService: UtilService,
    public interfaceService: PagesService,
    private socket: SocketService,
    private nzMessageService: NzMessageService,
    public request: RequestService,
  ) {
    this.messageSubject = new Subject();
    console.log('开始心跳检测');
    // 进入程序就进行心跳检测,避免出现开始就连接中断,后续不重连
    this.heartCheckStart();
    this.calcRunTime();
  }

  /**
   * 发送消息
   * @param message 发送消息
   */
  sendMessage(message) {
    this.webSocket.send(message);
  }

  /**
   * 创建新连接
   * @param url 要连接的url
   */
  connect(url) {
    if (!!url) {
      this.url = url;
    }
    // 创建websocket对象
    this.createWebSocket();
  }

  /**
   * 创建连接
   */
  createWebSocket() {
    // 如果没有建立过连接，才建立连接并且添加时间监听
    this.webSocket = new WebSocket(this.url);
    // 建立连接成功
    this.webSocket.onopen = (e) => this.onOpen(e);
    // 接收到消息
    this.webSocket.onmessage = (e) => this.onMessage(e);
    // 连接关闭
    this.webSocket.onclose = (e) => this.onClose(e);
    // 异常
    this.webSocket.onerror = (e) => this.onError(e);
  }

  /**
   * 连接打开
   * @param e 打开事件
   */
  onOpen(e) {
    this.notification.config({
      nzPlacement: 'bottomRight'
    });
    console.log('websocket 已连接');
    // 设置连接成功
    this.connectSuccess = true;
    // 如果是重连中
    if (this.reconnectFlag) {
      // 1.停止重连
      this.stopReconnect();
      // 2.重新开启心跳
      this.heartCheckStart();
      // 3.重新开始计算运行时间
      this.calcRunTime();
    }
  }

  msgList=[];
  msgData=[];
  ws: WebSocket;//定义websocket
  /**
   * 接受到消息
   */
  onMessage(e) {
    this.msgData = JSON.parse(e['data'])
    this.msgList.push(JSON.parse(e['data']))
    if(this.msgData['msgScp'] == 'loginOut'){
      // if (this.ws != null) { this.ws.close() };
      layer.msg('您的账号已在其它地方登录！');
      this.logout();
    }else if(this.msgData['msgScp'] == 'userOut'){
      layer.msg('该用户账户异常！');
      this.logout();
    }else if(this.msgData['msgScp'] == 'domainOut'){
      layer.msg('该用户登录领域异常！');
      this.logout();
    }else {
      /**
       * 获取未读通知数量
       */
      this.request.getUnread().subscribe((data)=>{
        this.sendMessages(data.object);
      });
      
      this.notification.blank('消息提醒','<a class=msgC' + this.msgData['msgId'] + ' rev="' + this.msgData['num']
       + '" rel="' + this.msgData['url'] + '?privId=' + this.msgData['privId'] + '">'
         + this.msgData['msgScp'] + '</a>', { nzDuration: 10000 });
      $('a.msgC' + this.msgData['msgId']).click((obj) => {
        localStorage.setItem('num', obj['target']['rev']);
        this.interfaceService.postPage('/erp/sysMsg/updateIsRead',{msgId:obj['target']['rev']}).subscribe((data: any) => {
          if (this.interfaceService.codeValidation(data)) {
          if(data.code==200){
            this.request.getUnread().subscribe((datas)=>{
              this.sendMessages(datas.object);
            });
            this.utilService.goTo(obj['target']['rel']);
          }
        }
        });
      });
      this.webSocket.send('前端推送信息-> '+JSON.stringify(this.msgData));
      this.messageSubject.next(this.msgData);
    }
    
  }

  logout() {
    setTimeout(() => {
      this.interfaceService.postPage('/erp/user/logout', {userIdByWebSocket:localStorage.getItem("userIdByWebSocket")}).subscribe((data: any) => {
        if (this.interfaceService.codeValidation(data)) {
        this.nzMessageService.info(data.message);
        this.utilService.goTo('/auth/login');
        }
      });
    }, 3000);
  }


  /**
   * 连接关闭
   */
  private onClose(e) {
    console.log('连接关闭', e);
    this.connectSuccess = false;
    this.webSocket.close();
    // 关闭时开始重连
    this.reconnect();
    this.stopRunTime();
    // throw new Error('webSocket connection closed:)');
  }

  /**
   * 连接异常
   */
  private onError(e) {
    // 出现异常时一定会进onClose,所以只在onClose做一次重连动作
    console.log('连接异常', e);
    this.connectSuccess = false;
    // throw new Error('webSocket connection error:)');
  }

  /**
   * 开始重新连接
   */
  reconnect() {
    // 如果已重连,则直接return,避免重复连接
    if (this.connectSuccess) {
      this.stopReconnect();
      console.log('已经连接成功,停止重连');
      return;
    }
    // 如果正在连接中,则直接return,避免产生多个轮训事件
    if (this.reconnectFlag) {
      console.log('正在重连,直接返回');
      return;
    }
    // 开始重连
    this.reconnectFlag = true;
    // 如果没能成功连接,则定时重连
    this.reconnectSubscription = interval(this.reconnectPeriod).subscribe(async (val) => {
      if(localStorage.getItem('login') === 'login'){
        console.log(`重连:${val}次`);
        const url = this.url;
        // 重新连接
        this.connect(url);
      }
    });    
  }

  /**
   * 停止重连
   */
  stopReconnect() {
    // 连接标识置为false
    this.reconnectFlag = false;
    // 取消订阅
    if (typeof this.reconnectSubscription !== 'undefined' && this.reconnectSubscription != null) {
      this.reconnectSubscription.unsubscribe();
    }
  }

  /**
   * 开始心跳检测
   */
  heartCheckStart() {
    this.serverTimeoutSubscription = interval(this.period).subscribe((val) => {
      if(localStorage.getItem('login') === 'login'){
        // 保持连接状态,重置下
        if (this.webSocket != null && this.webSocket.readyState === 1) {
          this.webSocket.send('前端推送信息-> ' + val);
          console.log(val, '连接状态，发送消息保持连接');
        } else {
          // 停止心跳
          this.heartCheckStop();
          // 开始重连
          this.reconnect();
          console.log('连接已断开,重新连接');
        }
      }
    });
    
  }

  /**
   * 停止心跳检测
   */
  heartCheckStop() {
    // 取消订阅停止心跳
    if (typeof this.serverTimeoutSubscription !== 'undefined' && this.serverTimeoutSubscription != null) {
      this.serverTimeoutSubscription.unsubscribe();
    }
  }

  /**
   * 开始计算运行时间
   */
  calcRunTime() {
    this.runTimeSubscription = interval(this.runTimePeriod).subscribe(period => {
      // console.log('运行时间', `${period}分钟`);
    });
  }

  /**
   * 停止计算运行时间
   */
  stopRunTime() {
    if (typeof this.runTimeSubscription !== 'undefined' && this.runTimeSubscription !== null) {
      this.runTimeSubscription.unsubscribe();
    }
  }
}